<?php
// Filename : SI.g11n.Encoding.UTF8.php
// Author : Cyrus Hackford (cyrus@cyrush.kr)
// Category : SI > Globalization(g11n) > Encoding > UTF-8

final class UTF8 {
	
	public static function Char2Int($siclUtf8Char) {
		$siclDiscInt=ord($siclUtf8Char)>>4;
		if(($siclDiscInt>>3)===0) // 1byte; U+00 ~ U+7F
			$siclCodePtInt=ord($siclUtf8Char);
		elseif(($siclDiscInt>>1)===6) // 2bytes; U+80 ~ U+7FF
			$siclCodePtInt=((ord($siclUtf8Char)^192)<<6)^(ord($siclUtf8Char[1])^128);
		elseif($siclDiscInt===14) // 3bytes; U+800 ~ U+FFFF
			$siclCodePtInt=((ord($siclUtf8Char)^224)<<12)^((ord($siclUtf8Char[1])^128)<<6)^(ord($siclUtf8Char[2])^128);
		elseif($siclDiscInt===15) // 4bytes; U+10000 ~ U+10FFFF
			$siclCodePtInt=((ord($siclUtf8Char)^240)<<18)^((ord($siclUtf8Char[1])^128)<<12)^((ord($siclUtf8Char[2])^128)<<6)^(ord($siclUtf8Char[3])^128);
		unset($siclUtf8Char,$siclDiscInt);
		
		return $siclCodePtInt;
	}
	
	public static function GetCharLength($siclHeadByteInt) {
		$siclVerifierInt=ord($siclHeadByteInt)>>3;
		$siclVerifiedInt=0;
		if($siclVerifierInt>=0 && $siclVerifierInt<=15)
			$siclVerifiedInt=1;
		elseif($siclVerifierInt>=24 && $siclVerifierInt<=27)
			$siclVerifiedInt=2;
		elseif($siclVerifierInt>=28 && $siclVerifierInt<=29)
			$siclVerifiedInt=3;
		elseif($siclVerifierInt===30)
			$siclVerifiedInt=4;
		unset($siclHeadByteInt,$siclVerifierInt);
		
		return $siclVerifiedInt;
	}
	
	public static function Int2Char($siclCodePtInt) {
		$i=$siclCodePtInt;
		if($siclCodePtInt>=0 && $siclCodePtInt<=127)
			$siclUtf8Char=chr($siclCodePtInt);
		elseif($siclCodePtInt>=128 && $siclCodePtInt<=2047)
			$siclUtf8Char=chr(($siclTmpEinsInt=($siclCodePtInt>>6))^192).chr(($siclCodePtInt^($siclTmpEinsInt<<6))^128);
		elseif($siclCodePtInt>=2048 && $siclCodePtInt<=65535)
			$siclUtf8Char=chr(($siclTmpEinsInt=($siclCodePtInt>>12))^224).chr(($siclTmpDreiInt=($siclTmpZweiInt=($siclCodePtInt^($siclTmpEinsInt<<12)))>>6)^128).chr(($siclTmpZweiInt^($siclTmpDreiInt<<6))^128);
		elseif($siclCodePtInt>=65536 && $siclCodePtInt<=1114111)
			$siclUtf8Char=chr(($siclTmpEinsInt=($siclCodePtInt>>18))^240).chr(($siclTmpDreiInt=($siclTmpZweiInt=($siclCodePtInt^($siclTmpEinsInt<<18)))>>12)^128).chr(($siclTmpFuenfInt=($siclTmpVierInt=($siclTmpZweiInt^($siclTmpDreiInt<<12)))>>6)^128).chr(($siclTmpVierInt^($siclTmpFuenfInt<<6))^128);
		unset($siclCodePtInt,$siclTmpEinsInt,$siclTmpZweiInt,$siclTmpDreiInt,$siclTmpVierInt,$siclTmpFuenfInt);
		
		return $siclUtf8Char;
	}
	
	public static function Length($siclTextStr) {
		$siclTextLengthInt=strlen($siclTextStr);
		for($siclLoopInt=$siclCharCtInt=0;$siclLoopInt<$siclTextLengthInt;$siclCharCtInt++) {
			$siclVerifyInt=ord($siclTextStr[$siclLoopInt]);
			if($siclVerifyInt<128)
				$siclLoopInt++;
			elseif($siclVerifyInt<224)
				$siclLoopInt+=2;
			elseif($siclVerifyInt<240)
				$siclLoopInt+=3;
			elseif($siclVerifyInt<248)
				$siclLoopInt+=4;
		}
		unset($siclTextStr,$siclTextLengthInt,$siclLoopInt);
		
		return $siclCharCtInt;
	}
	
	public static function Slice($siclTextStr,$siclLengthInt=255) {
		if(strlen($siclTextStr)<=$siclLengthInt)
			return $siclTextStr;
		
		$siclVerifyInt=ord($siclTextStr[$siclLengthInt-1])>>6;
		if(($siclVerifyInt>>1)===0) // 1byte
			$siclLocationSubtInt=0;
		elseif($siclVerifyInt===3) // Head byte of multi-bytes characters.
			$siclLocationSubtInt=1;
		elseif($siclVerifyInt===2) { // Middle of multi-bytes character.
			for($siclLoopInt=2;$siclLengthInt>=$siclLoopInt;$siclLoopInt++) { // Seeking for head byte.
				if((ord($siclTextStr[$siclLengthInt-$siclLoopInt])>>6)!==2)
					break;
			}
			switch(ord($siclTextStr[$siclLengthInt-$siclLoopInt])>>4) { // Identify the length of current character.
				case 12:
				case 13:
					$siclVerifiedLengthInt=2;
					break;
				case 14:
					$siclVerifiedLengthInt=3;
					break;
				case 15:
					$siclVerifiedLengthInt=4;
					break;
			}
			if($siclLoopInt===$siclVerifiedLengthInt) // The byte we're verifying is the last byte of the character.
				$siclLocationSubtInt=0;
			else
				$siclLocationSubtInt=$siclLoopInt;
			unset($siclLoopInt,$siclVerifiedLengthInt);
		}
		$siclSlicedStr=substr($siclTextStr,0,$siclLengthInt-$siclLocationSubtInt);
		unset($siclTextStr,$siclLengthInt,$siclLocationSubtInt);
		
		return $siclSlicedStr;
	}
	
	public static function SliceByChar($siclTextStr,$siclLengthInt=255) { // Under implementation.
		/*if(UTF8::Length($siclTextStr)<=$siclLengthInt)
			return $siclTextStr;
		
		$siclCharLenInt=$siclLoopInt=0;
		while($siclCharLenInt<=$siclLengthInt) {
			if((ord($siclTextStr[$siclLoopInt])>>6)!==2)
				$siclCharLenInt++;
			$siclLoopInt++;
		}
		$siclSlicedStr=substr($siclTextStr,0,--$siclLoopInt);
		unset($siclTextStr,$siclLengthInt,$siclCharLenInt,$siclLoopInt);
		
		return $siclSlicedStr;*/
		return false;
	}
	
	public static function VerifyIntegrity($siclTextStr) { // Under implementation.
		return false;
	}
	
}

?>